#pragma once

#include <iostream>

class Matrix {
public:
    Matrix(int m, int n);
    Matrix(Matrix &&a);
    // For now we'll avoid the copy constructor.
    Matrix(const Matrix &a);

    Matrix& operator=(const Matrix &a);
    ~Matrix();

    double  operator()(int i, int j) const;
    double& operator()(int i, int j);

    template<class V> void set_row(int i, const V& row);
    template<class V> void set_col(int i, const V& col);

    int rows() const { return _rows; }
    int cols() const { return _cols; }
    int size() const { return rows()*cols(); }

private:
    double *_data;
    int _rows, _cols;

};

inline Matrix::Matrix(int m, int n) 
  : _data(m*n>0 ? new double[m*n] : 0),
    _rows(m), _cols(n)
{}

inline Matrix::Matrix(Matrix &&a) {
    _data = a._data;
    _rows = a._rows;
    _cols = a._cols;
    a._data = 0;
}

inline Matrix::~Matrix() { delete _data; }

// Note: matrices are column-major ordered.
inline double Matrix::operator()(int i, int j) const {
    return _data[i + rows()*j];
}
inline double& Matrix::operator()(int i, int j)  {
    return _data[i + rows()*j];
}

template<class V> 
inline void Matrix::set_row(int i, const V &row) {
    for (int j=0; j<cols(); ++j)
        (*this)(i,j) = row(j);
}
template<class V> 
inline void Matrix::set_col(int j, const V& col) {
    for (int i=0; i<rows(); ++i) 
        (*this)(i,j) = col(i);
}

template <class ostream>
inline ostream& operator<<(ostream &o, const Matrix &x) {
    for (int i=0; i<x.rows(); ++i) {
        if (i>0) o << "\n";
        for (int j=0; j<x.cols(); ++j) {
            if (j>0) o << "\t";
            o << x(i,j);
        }
    }
    return o;
}

